package controllers

import models._
import play.api._
import play.api.mvc._
import com.workday.gridsimulator._
import play.api.data._
import play.api.data.Forms._
import play.api.libs.iteratee.Iteratee
import play.api.libs.iteratee.Enumerator

import akka.actor._
import akka.util.duration._

import play.api._
import play.api.libs.json._
import play.api.libs.iteratee._
import play.api.libs.concurrent._

import akka.util.Timeout
import akka.pattern.ask
import akka.dispatch.Await
import play.api.Play.current
import com.workday.gridsimulator.JsonHelper
import com.codahale.jerkson.ParsingException

object Application extends Controller {

  var args: Array[String] = _
  implicit val timeout = Timeout(5 seconds)
  var gs: ActorRef = null

  val simForm = Form(
    tuple(
      "simType" -> nonEmptyText,
      "WorkerCount" -> nonEmptyText,
      "JobCount" -> nonEmptyText,
      "ArrivalRate" -> nonEmptyText,
      "avgLength" -> nonEmptyText,
      "ec2InstanceSize" -> nonEmptyText))

  def index = Action {
    Ok(views.html.index())
    // Redirect(routes.Application.sim)
  }

  def sim = Action { implicit request =>
    //StaticGridSim.main(null)
    Ok(views.html.simulate(simForm))
  }

  def simulate = Action { implicit request =>
    simForm.bindFromRequest.fold(
      errors => BadRequest(views.html.simulate(errors)),
      formValues => {
        val (simType, workerCount, jobCount, arrivalRate, avgLength, ec2InstanceSize) = formValues
        args = Array(simType, workerCount, jobCount, arrivalRate, avgLength, ec2InstanceSize)
        runSimulation(simType, workerCount, jobCount, arrivalRate, avgLength, ec2InstanceSize)
        Ok(views.html.sim(simType, workerCount, jobCount, arrivalRate, avgLength, ec2InstanceSize))
      })
  }

  private def runSimulation(simType: String, workerCount: String, jobCount: String, arrivalRate: String, avgLength: String, ec2InstanceSize: String) = {

    try {
      val schedulerSubmissionLimitOption = Play.application.configuration.getString("workSubmissionLimit")
      val schedulerSubmissionLimit: String = schedulerSubmissionLimitOption.getOrElse("100")
      println("LIMIT: " + schedulerSubmissionLimit)

      gs = Akka.system.actorOf(Props(new GridSim(SimpleJobCreation, schedulerSubmissionLimit.toInt)), name = "SIM")
    } catch {
      case e: InvalidActorNameException =>
        gs = Akka.system.actorFor("akka://application/user/SIM")
        gs ! "Prepare"
    }
  }

  def webSocketCreation = WebSocket.async[JsValue] { request =>
    val updateMeAfterThisManyCompletitions = Play.application.configuration.getString("updateMeAfterThisManyCompletitions")
    val updateMeAfterThisManyCompletitionsValue: String = updateMeAfterThisManyCompletitions.getOrElse("100")
    SimStatus.start(gs, args, updateMeAfterThisManyCompletitionsValue.toInt)
  }

  def uploadPage = Action { implicit request =>
    Ok(views.html.upload())
  }

  def uploaded(filePath: String) = Action { implicit request =>
    var exception = ""
    var jsonGridDetails: GridDetails = null
    try {
      jsonGridDetails = JsonHelper.parseGridFromFile(filePath)
      //val map = Map(("WorkerCount", wc), ("JobCount", jc))
      val map = Map(("simType", jsonGridDetails.simType), ("WorkerCount", jsonGridDetails.workerCount), ("JobCount", jsonGridDetails.jobCount),
        ("ArrivalRate", jsonGridDetails.arrivalRate), ("avgLength", jsonGridDetails.avgLength), ("ec2InstanceSize", jsonGridDetails.ec2InstanceSize))
      //simForm = simForm.fill(jsonGridDetails.simType, jsonGridDetails.simType, jsonGridDetails.simType, jsonGridDetails.simType, jsonGridDetails.simType, jsonGridDetails.simType, jsonGridDetails.simType)    
      Ok(views.html.jsonRender(simForm, map, ""))
    } catch {
      case pe: ParsingException =>
        exception = "INVALID JSON SYNTAX"
        Ok(views.html.jsonRender(simForm, null, exception))

    }

  }

  def upload = Action(parse.multipartFormData) { request =>
    request.body.file("jsonFile").map { jsonFile =>
      import java.io.File
      val fileName = jsonFile.filename
      val contentType = jsonFile.contentType
      val filePath = "./public/uploads/" + fileName
      jsonFile.ref.moveTo(new File(filePath), true)

      // Ok("File uploaded")
      Redirect(routes.Application.uploaded(filePath))
    }.getOrElse {
      Redirect(routes.Application.index).flashing(
        "error" -> "Missing file")
    }
  }

  def serveJsonFileForGrid(simType: String, workerCount: String, jobCount: String, arrivalRate: String, avgLength: String, ec2InstanceSize: String) = Action {
    val filePath = "./tmp/" + System.currentTimeMillis() + ".json"
    filePath.trim()
    val file = JsonHelper.generateGridJsonFile(simType, workerCount, jobCount, arrivalRate, avgLength, ec2InstanceSize, filePath)
    Ok.sendFile(file)
  }

  def listUploadedGrids() = Action {
    //get the list of all JSON files in public/uploads
    var grids: List[String] = List()
    for (file <- new java.io.File("./public/uploads").listFiles) {
      grids = grids ::: List(file.getPath())
      println(file.getPath)
    }
    //render the list on the page
    Ok(views.html.listUploads(grids))
  }

}